﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security.Cryptography;
using CarbonExchange.Bll;
using CarbonExchange.Bll.Exceptions;

namespace CarbonExchange.Tests
{
    /// <summary>
    /// Summary description for UsersTest
    /// </summary>
    [TestClass]
    public class UsersTest : BaseTest
    {
        public UsersTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }


        [TestMethod]
        public void User_GetById_ReturnsNull_WithIncorrectId()
        {
            var factory = new UserFactory(_Context);
            Assert.IsNull(factory.GetById(int.MaxValue));
        }

        [TestMethod]
        public void User_GetById_ReturnsNotNull_WithCorrectId()
        {
            var factory = new UserFactory(_Context);
            var tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(tmp);
        }

        [TestMethod]
        public void User_GetBySiteId_ReturnsEmptyList_WithIncorrectSiteId()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.AreEqual(0, factory.GetAllBySiteId(int.MaxValue).Count());
        }

        [TestMethod]
        public void User_GetBySiteId_ReturnsPopulatedList_WithCorrectSiteId()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.AreEqual(_TestUsers.Count(), factory.GetAllBySiteId(_TestSite.Id).Count());
        }

        [TestMethod]
        public void User_GetById_ReturnsCorrectProperties()
        {
            UserFactory factory = new UserFactory(_Context);
            User tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(tmp);
            Assert.AreEqual("Test", tmp.FirstName);
            Assert.AreEqual("User 0", tmp.LastName);
            Assert.AreEqual("Comment 0", tmp.Comment);
            Assert.AreEqual(_TestCountries[0].Id, tmp.CountryId);
            Assert.AreEqual(DateTime.Parse("24/10/1970 12:00:00"), tmp.Created);
            Assert.AreEqual("Department 0", tmp.Department);
            Assert.AreEqual("testemail0@email.com", tmp.EmailAddress);
            Assert.AreEqual(true, tmp.EmailAuthenticated);
            Assert.AreEqual(_TestUsers[0].Salt, tmp.Salt);
            Assert.AreEqual(_TestUsers[0].Password, tmp.EncodedPassword);
            Assert.AreEqual(false, tmp.Relative);
            Assert.AreEqual("State0", tmp.State);
            Assert.AreEqual(100, tmp.ThumnailId);
            Assert.AreEqual(_TestSite.Id, tmp.SiteId);
            Assert.AreEqual(true, tmp.Anon);
            
        }

        [TestMethod]
        public void User_GetAllBySiteId_ReturnsCorrectProperties()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetAllBySiteId(_TestSite.Id).ToList()[0];
            Assert.AreEqual("Test", tmp.FirstName);
            Assert.AreEqual("User 0", tmp.LastName);
            Assert.AreEqual("Comment 0", tmp.Comment);
            Assert.AreEqual(_TestCountries[0].Id, tmp.CountryId);
            Assert.AreEqual(DateTime.Parse("24/10/1970 12:00:00"), tmp.Created);
            Assert.AreEqual("Department 0", tmp.Department);
            Assert.AreEqual("testemail0@email.com", tmp.EmailAddress);
            Assert.AreEqual(true, tmp.EmailAuthenticated);
            Assert.AreEqual(_TestUsers[0].Salt, tmp.Salt);
            Assert.AreEqual(_TestUsers[0].Password, tmp.EncodedPassword);
            Assert.AreEqual(false, tmp.Relative);
            Assert.AreEqual("State0", tmp.State);
            Assert.AreEqual(100, tmp.ThumnailId);
            Assert.AreEqual(_TestSite.Id, tmp.SiteId);
            Assert.AreEqual(true, tmp.Anon);
        }

        [TestMethod]
        public void User_InsertOne()
        {
            UserFactory factory = new UserFactory(_Context);
            User tmp = new User(_TestSite.Id);
            tmp.Anon = false;
            tmp.Comment = "Comment";
            tmp.CountryId = _TestCountries[0].Id;
            tmp.Department = "Dept";
            tmp.EmailAddress = "TestEmailAddress@email.com";
            tmp.FirstName = "Oliver";
            tmp.LastName = "Armfelt";
            tmp.Relative = false;
            tmp.State = "Utah";
            tmp.ThumnailId = 1;
            tmp.SetPassword(null, "Password1");
            var tmpEncodedPassword = tmp.EncodedPassword;
            var tmpSalt = tmp.Salt;

            DateTime expectedDateTime = DateTime.Now;
            factory.Save(tmp);

            Assert.IsTrue(tmp.Id > 0);
            Assert.AreEqual(false, tmp.Anon);
            Assert.AreEqual("Comment", tmp.Comment);
            Assert.AreEqual(1, tmp.CountryId);
            Assert.AreEqual("Dept", tmp.Department);
            Assert.AreEqual("TestEmailAddress@email.com", tmp.EmailAddress);
            Assert.AreEqual("Oliver", tmp.FirstName);
            Assert.AreEqual("Armfelt", tmp.LastName);
            Assert.AreEqual(false, tmp.Relative);
            Assert.AreEqual("Utah", tmp.State);
            Assert.AreEqual(1, tmp.ThumnailId);
            Assert.AreEqual(tmpEncodedPassword, tmp.EncodedPassword);
            Assert.AreEqual(tmpSalt, tmp.Salt);
            Assert.AreEqual(_TestSite.Id, tmp.SiteId);
            
            int id = tmp.Id;

            User tmp2 = factory.GetById(id);
            Assert.IsNotNull(tmp2);
            Assert.AreEqual(tmp.Anon, tmp2.Anon);
            Assert.AreEqual(tmp.Comment, tmp2.Comment);
            Assert.AreEqual(tmp.CountryId, tmp2.CountryId);
            Assert.AreEqual(tmp.Department, tmp2.Department);
            Assert.AreEqual(tmp.EmailAddress, tmp2.EmailAddress);
            Assert.AreEqual(tmp.FirstName, tmp2.FirstName);
            Assert.AreEqual(tmp.LastName, tmp2.LastName);
            Assert.AreEqual(tmp.Relative, tmp2.Relative);
            Assert.AreEqual(tmp.State, tmp2.State);
            Assert.AreEqual(tmp.ThumnailId, tmp2.ThumnailId);
            Assert.AreEqual(tmp.EncodedPassword, tmp2.EncodedPassword);
            Assert.AreEqual(tmp.Salt, tmp2.Salt);
            Assert.AreEqual(tmp.SiteId, tmp2.SiteId);

        }

        [TestMethod]
        public void User_InsertMany()
        {
            UserFactory factory = new UserFactory(_Context);

            int existingCount = factory.GetAllBySiteId(_TestSite.Id).Count();
            int loopCount = 5;
            var updates = new List<User>();
            var tmpEncodedPasswords = new Dictionary<string, int>();
            for (int i = 0; i < loopCount; i++)
            {
                var tmp = new User(_TestSite.Id);
                tmp.Anon = false;
                tmp.Comment = string.Format("Insert Comment {0}", i);
                tmp.CountryId = _TestCountries[i % 2 == 0 ? 1 : 0].Id;
                tmp.Department = string.Format("Test Dept {0}", i);
                tmp.EmailAddress = string.Format("TestEmailAddress{0}@email.com", i);
                tmp.FirstName = string.Format("Oliver {0}", i);
                tmp.LastName = string.Format("Armfelt {0}", i);
                tmp.Relative = i % 2 == 0 ? true : false;
                tmp.State = string.Format("Utah {0}", i);
                tmp.ThumnailId = i * 2;
                tmp.SetPassword(null, "Password1");
                tmpEncodedPasswords.Add(tmp.EncodedPassword, tmp.Salt);
                updates.Add(tmp);
            }

            DateTime expectedDateTime = DateTime.Now;
            factory.Save(updates.AsQueryable());
            int[] tmpIds = new int[loopCount];

            for (int i = 0; i < loopCount; i++)
            {
                tmpIds[i] = updates[i].Id;
                Assert.IsTrue(updates[i].Id > 0);
                Assert.AreEqual(false, updates[i].Anon);
                Assert.AreEqual(string.Format("Insert Comment {0}", i), updates[i].Comment);
                Assert.AreEqual(_TestCountries[i % 2 == 0 ? 1 : 0].Id, updates[i].CountryId);
                Assert.AreEqual(string.Format("Test Dept {0}", i), updates[i].Department);
                Assert.AreEqual(string.Format("TestEmailAddress{0}@email.com", i), updates[i].EmailAddress);
                Assert.AreEqual(string.Format("Oliver {0}", i), updates[i].FirstName);
                Assert.AreEqual(string.Format("Armfelt {0}", i), updates[i].LastName);
                Assert.AreEqual(i % 2 == 0 ? true : false, updates[i].Relative);
                Assert.AreEqual(string.Format("Utah {0}", i), updates[i].State);
                Assert.AreEqual(i * 2, updates[i].ThumnailId);
                Assert.AreEqual(tmpEncodedPasswords.Keys.ElementAt(i), updates[i].EncodedPassword);
                Assert.AreEqual(tmpEncodedPasswords[tmpEncodedPasswords.Keys.ElementAt(i)], updates[i].Salt);
                Assert.AreEqual(_TestSite.Id, updates[i].SiteId);
            }

            var saved = factory.GetAllBySiteId(_TestSite.Id).ToList().OrderBy(x => x.Id).Skip(existingCount).ToArray();
            Assert.AreEqual(loopCount, saved.Count());
            for (int i = 0; i < saved.Count(); i++)
            {
                Assert.AreEqual(tmpIds[i], saved[i].Id);
                Assert.AreEqual(false, updates[i].Anon);
                Assert.AreEqual(string.Format("Insert Comment {0}", i), updates[i].Comment);
                Assert.AreEqual(_TestCountries[i % 2 == 0 ? 1 : 0].Id, updates[i].CountryId);
                Assert.AreEqual(string.Format("Test Dept {0}", i), updates[i].Department);
                Assert.AreEqual(string.Format("TestEmailAddress{0}@email.com", i), updates[i].EmailAddress);
                Assert.AreEqual(string.Format("Oliver {0}", i), updates[i].FirstName);
                Assert.AreEqual(string.Format("Armfelt {0}", i), updates[i].LastName);
                Assert.AreEqual(i % 2 == 0 ? true : false, updates[i].Relative);
                Assert.AreEqual(string.Format("Utah {0}", i), updates[i].State);
                Assert.AreEqual(i * 2, updates[i].ThumnailId);
                Assert.AreEqual(tmpEncodedPasswords.Keys.ElementAt(i), updates[i].EncodedPassword);
                Assert.AreEqual(tmpEncodedPasswords[tmpEncodedPasswords.Keys.ElementAt(i)], updates[i].Salt);
            }
        }

        [TestMethod]
        public void User_UpdateOne()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(tmp);

            tmp.Anon = false;
            tmp.Comment = "Update Comment";
            tmp.CountryId = _TestCountries[1].Id;
            tmp.Department = "Update Test Dept";
            tmp.EmailAddress = "UpdateTestEmailAddress@email.com";
            tmp.FirstName = "Insert First Name";
            tmp.LastName = "Insert Last Name";
            tmp.Relative = true;
            tmp.State = "Update Utah";
            tmp.ThumnailId = 77;
            tmp.SetPassword("Encoded0", "NewPassword");
            var tmpEncodedPassword = tmp.EncodedPassword;
            var tmpSalt = tmp.Salt;

            factory.Save(tmp);

            Assert.AreEqual(_TestUsers[0].Id, tmp.Id);
            Assert.AreEqual(false, tmp.Anon);
            Assert.AreEqual("Update Comment", tmp.Comment);
            Assert.AreEqual(_TestCountries[1].Id, tmp.CountryId);
            Assert.AreEqual("Update Test Dept", tmp.Department);
            Assert.AreEqual("UpdateTestEmailAddress@email.com", tmp.EmailAddress);
            Assert.AreEqual("Insert First Name", tmp.FirstName);
            Assert.AreEqual("Insert Last Name", tmp.LastName);
            Assert.AreEqual(true, tmp.Relative);
            Assert.AreEqual("Update Utah", tmp.State);
            Assert.AreEqual(77, tmp.ThumnailId);
            Assert.AreEqual(tmpEncodedPassword, tmp.EncodedPassword);
            Assert.AreEqual(tmpSalt, tmp.Salt);
            Assert.AreEqual(_TestSite.Id, tmp.SiteId);

            tmp = factory.GetById(_TestUsers[0].Id);

            Assert.AreEqual(_TestUsers[0].Id, tmp.Id);
            Assert.AreEqual(false, tmp.Anon);
            Assert.AreEqual("Update Comment", tmp.Comment);
            Assert.AreEqual(_TestCountries[1].Id, tmp.CountryId);
            Assert.AreEqual("Update Test Dept", tmp.Department);
            Assert.AreEqual("UpdateTestEmailAddress@email.com", tmp.EmailAddress);
            Assert.AreEqual("Insert First Name", tmp.FirstName);
            Assert.AreEqual("Insert Last Name", tmp.LastName);
            Assert.AreEqual(true, tmp.Relative);
            Assert.AreEqual("Update Utah", tmp.State);
            Assert.AreEqual(77, tmp.ThumnailId);
            Assert.AreEqual(tmpEncodedPassword, tmp.EncodedPassword);
            Assert.AreEqual(tmpSalt, tmp.Salt);
            Assert.AreEqual(_TestSite.Id, tmp.SiteId);
        }

        [TestMethod]
        public void User_UpdateMany()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetAllBySiteId(_TestSite.Id).ToArray().OrderBy(x => x.Id);
            var count = factory.CountAllBySiteId(_TestSite.Id);
            var tmpEncodedPasswords = new string[count];
            var tmpSalts = new int[count];
            int i = 0;

            foreach (User user in tmp.AsEnumerable())
            {
                Assert.AreEqual(i % 4 == 0 ? true : false, user.Anon);
                user.Anon = i % 4 == 0 ? false : true;
                user.Comment = string.Format("Update Comment {0}", i);
                Assert.AreEqual(_TestCountries[i % 2 == 0 ? 0 : 1].Id, user.CountryId);
                user.CountryId = _TestCountries[i % 2 == 0 ? 1 : 0].Id;
                user.Department = string.Format("Update Test Dept {0}", i);
                user.EmailAddress = string.Format("UpdateTestEmailAddress@email{0}.com", i);
                user.FirstName = string.Format("Update First Name {0}", i);
                user.LastName = string.Format("Update Last Name", i);
                Assert.AreEqual(i % 3 == 0 ? false : true, user.Relative);
                user.Relative = i % 3 == 0 ? true : false;
                user.State = string.Format("Update Utah {0}", i);
                user.ThumnailId = i * 4;
                user.SetPassword(string.Format("Encoded{0}", i), string.Format("Password{0}", i));
                tmpEncodedPasswords[i] = user.EncodedPassword;
                tmpSalts[i] = user.Salt;
                i++;
            }

            factory.Save(tmp.AsQueryable());

            i = 0; 
            foreach (User user in tmp)
            {
                Assert.AreEqual(_TestUsers[i].Id, user.Id);
                Assert.AreEqual(i % 4 == 0 ? false : true, user.Anon);
                Assert.AreEqual(string.Format("Update Comment {0}", i), user.Comment);
                Assert.AreEqual(_TestCountries[i % 2 == 0 ? 1 : 0].Id, user.CountryId);
                Assert.AreEqual(string.Format("Update Test Dept {0}", i), user.Department);
                Assert.AreEqual(string.Format("UpdateTestEmailAddress@email{0}.com", i), user.EmailAddress);
                Assert.AreEqual(string.Format("Update First Name {0}", i), user.FirstName);
                Assert.AreEqual(string.Format("Update Last Name", i), user.LastName);
                Assert.AreEqual(i % 3 == 0 ? true : false, user.Relative);
                Assert.AreEqual(string.Format("Update Utah {0}", i), user.State);
                Assert.AreEqual(i * 4, user.ThumnailId);
                Assert.AreEqual(tmpEncodedPasswords[i], user.EncodedPassword);
                Assert.AreEqual(tmpSalts[i], user.Salt);
                Assert.AreEqual(_TestSite.Id, user.SiteId);
                i++;
            }
            tmp = factory.GetAllBySiteId(_TestSite.Id).ToArray().OrderBy(x => x.Id);

            i = 0; 
            foreach (User user in tmp)
            {
                Assert.AreEqual(_TestUsers[i].Id, user.Id);
                Assert.AreEqual(i % 4 == 0 ? false : true, user.Anon);
                Assert.AreEqual(string.Format("Update Comment {0}", i), user.Comment);
                Assert.AreEqual(_TestCountries[i % 2 == 0 ? 1 : 0].Id, user.CountryId);
                Assert.AreEqual(string.Format("Update Test Dept {0}", i), user.Department);
                Assert.AreEqual(string.Format("UpdateTestEmailAddress@email{0}.com", i), user.EmailAddress);
                Assert.AreEqual(string.Format("Update First Name {0}", i), user.FirstName);
                Assert.AreEqual(string.Format("Update Last Name", i), user.LastName);
                Assert.AreEqual(i % 3 == 0 ? true : false, user.Relative);
                Assert.AreEqual(string.Format("Update Utah {0}", i), user.State);
                Assert.AreEqual(i * 4, user.ThumnailId);
                Assert.AreEqual(tmpEncodedPasswords[i], user.EncodedPassword);
                Assert.AreEqual(tmpSalts[i], user.Salt);
                Assert.AreEqual(_TestSite.Id, user.SiteId);
                i++;
            }
        }

        [TestMethod]
        public void User_DeleteOne()
        {
            UserFactory factory = new UserFactory(_Context);
            User User = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(User);
            factory.Delete(User);
            Assert.AreEqual(_TestUsers.Count()-1, factory.GetAllBySiteId(_TestSite.Id).Count());
            User = factory.GetById(_TestUsers[0].Id);
            Assert.IsNull(User);
        }

        [TestMethod]
        public void User_DeleteMany()
        {
            UserFactory factory = new UserFactory(_Context);
            var Users = factory.GetAllBySiteId(_TestSite.Id);
            Assert.IsTrue(Users.Count() > 1);
            factory.Delete(Users);
            Users = factory.GetAllBySiteId(_TestSite.Id);
            Assert.AreEqual(0, Users.Count());
        }

        [TestMethod]
        public void User_AuthenticatePassword_WithInCorrectPassword_ReturnsFalse()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(tmp);
            Assert.IsFalse(tmp.AuthenticatePassword("Rubbish"));
        }

        [TestMethod]
        public void User_AuthenticatePassword_WithCorrectPassword_ReturnsTrue()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsTrue(tmp.AuthenticatePassword("Password0"));
        }

        [TestMethod]
        public void User_SetPassword_WithInCorrectOriginalPassword_ReturnsFalse()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsFalse(tmp.SetPassword("PasswordRubbish", "NewPassword"));
        }

        [TestMethod]
        public void User_SetPassword_WithCorrectOriginalPassword_ReturnsTrueAndCreatedNewSaltAndNewEncodedPassword()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsTrue(tmp.SetPassword("Password0", "NewPassword"));
            Assert.AreNotEqual(_TestUsers[0].Salt, tmp.Salt);
            Assert.AreNotEqual(_TestUsers[0].Password, tmp.EncodedPassword);
        }

        [TestMethod]
        public void User_NewUser_EmailAuthenticate_IsFalse()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = new User(_TestSite.Id);
            Assert.IsFalse(tmp.EmailAuthenticated);
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void User_ValdiateWithEmptyEmailAddress_ThrowsException()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = new User(_TestSite.Id);
            tmp.Anon = true;
            tmp.Comment = "test";
            tmp.CountryId = 1;
            tmp.Department = "test";
            tmp.SetPassword(null, "Password1");
            tmp.State = "test";
            tmp.ThumnailId = 55;
            factory.Save(tmp);
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void User_ValdiateWithDuplicateEmailAddressInDB_ThrowsException()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = new User(_TestSite.Id);
            tmp.Anon = true;
            tmp.Comment = "test";
            tmp.CountryId = 1;
            tmp.Department = "test";
            tmp.SetPassword(null, "Password1");
            tmp.State = "test";
            tmp.ThumnailId = 55;
            tmp.FirstName = "test";
            tmp.LastName = "test";
            tmp.EmailAddress = "testValidateion@email.com";
            try
            {
                factory.Save(tmp);
            }
            catch(ValidationException)
            {
                throw new AssertInconclusiveException("Expected Excecptions To Be Thrown after second save");
            }
            var tmp2 = new User(_TestSite.Id);
            tmp2.Anon = true;
            tmp2.Comment = "test";
            tmp2.CountryId = 1;
            tmp2.Department = "test";
            tmp2.SetPassword(null, "Password1");
            tmp2.State = "test";
            tmp2.ThumnailId = 55;
            tmp2.FirstName = "test";
            tmp2.LastName = "test";
            tmp2.EmailAddress = "testValidateion@email.com";
            factory.Save(tmp2);
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void User_ValdiateWithDuplicateEmailAddressInUpdateing_ThrowsException()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = new User(_TestSite.Id);
            tmp.Anon = true;
            tmp.Comment = "test";
            tmp.CountryId = 1;
            tmp.Department = "test";
            tmp.SetPassword(null, "Password1");
            tmp.State = "test";
            tmp.ThumnailId = 55;
            tmp.FirstName = "test";
            tmp.LastName = "test";
            tmp.EmailAddress = "testValidateion@email.com";
            var tmp2 = new User(_TestSite.Id);
            tmp2.Anon = true;
            tmp2.Comment = "test";
            tmp2.CountryId = 1;
            tmp2.Department = "test";
            tmp2.SetPassword(null, "Password1");
            tmp2.State = "test";
            tmp2.ThumnailId = 55;
            tmp2.FirstName = "test";
            tmp2.LastName = "test";
            tmp2.EmailAddress = "testValidateion@email.com";
            factory.Save(new User[]{tmp, tmp2});
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void User_ValidateWithFirstNameNull_ThrowsException()
        {
            UserFactory factory = new UserFactory(_Context);
            User tmp = new User(_TestSite.Id);
            tmp.Anon = true;
            tmp.Comment = "test";
            tmp.CountryId = 1;
            tmp.Department = "test";
            tmp.SetPassword(null, "Password1");
            tmp.State = "test";
            tmp.ThumnailId = 55;
            tmp.LastName = "test";
            tmp.EmailAddress = "testValidateion@email.com";

            tmp.FirstName = "";
            factory.Save(tmp);
        }

        [TestMethod]
        [ExpectedException(typeof(ValidationException))]
        public void User_ValidateWithLastNameNull_ThrowsException()
        {
            UserFactory factory = new UserFactory(_Context);
            User tmp = new User(_TestSite.Id);
            tmp.EmailAddress = "testValidateion@email.com";
            tmp.Anon = true;
            tmp.Comment = "test";
            tmp.CountryId = 1;
            tmp.Department = "test";
            tmp.SetPassword(null, "Password1");
            tmp.State = "test";
            tmp.ThumnailId = 55;
            tmp.FirstName = "test";
            tmp.LastName = "";

            factory.Save(tmp);
        }

        [TestMethod]
        public void User_CountryPropertyReturnsCorrectCountryId()
        {
            UserFactory factory = new UserFactory(_Context);
            var user = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(user);
            Assert.IsNotNull(user.Country);
            Assert.AreEqual(user.CountryId, user.Country.Id);
            Assert.AreEqual("United Kingdom", user.Country.Name);
            Assert.AreEqual(DateTime.Parse("24/10/1975 12:00:00"), user.Country.Created);
            Assert.AreEqual(user.SiteId, user.Country.SiteId);
        }

        [TestMethod]
        public void User_SetCountryProperty_UpdatesCorrectly()
        {
            UserFactory factory = new UserFactory(_Context);
            var user = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(user);
            Assert.IsNotNull(user.Country);
            Assert.AreEqual(_TestCountries[0].Id, user.Country.Id);

            CountryFactory countries = new CountryFactory(_Context);
            user.Country = countries.GetById(_TestCountries[1].Id);

            Assert.AreEqual(_TestCountries[1].Id, user.Country.Id);
            Assert.AreEqual(_TestCountries[1].Id, user.CountryId);

            factory.Save(user);

            Assert.AreEqual(_TestCountries[1].Id, user.Country.Id);
            Assert.AreEqual(_TestCountries[1].Id, user.CountryId);

            user = factory.GetById(_TestUsers[0].Id);

            Assert.AreEqual(_TestCountries[1].Id, user.Country.Id);
            Assert.AreEqual(_TestCountries[1].Id, user.CountryId);
        }

        [TestMethod]
        [ExpectedException(typeof(Bll.Exceptions.ValidationException))]
        public void User_ValidationFails_WhenEmailAdressHasNoValidMatchInEmailRestrictions()
        {
            //reset first counry id to use in this test only
            _TestCountries[0].Site = _AlternateSite;
            _Context.SubmitChanges();

            EmailRestrictionFactory restrictionFactory = new EmailRestrictionFactory(_Context);
            UserFactory userFactory = new UserFactory(_Context);

            EmailRestriction restriction = new EmailRestriction(_AlternateSite.Id);
            restriction.EmailFilter = "[a-zA-Z0-9._]{0,}@testMail.com";
            restrictionFactory.Save(restriction);

            User tmp = new User(_AlternateSite.Id);
            tmp.EmailAddress = "hello@rubbish.com";
            tmp.FirstName = "First";
            tmp.LastName = "Last";
            tmp.CountryId = _TestCountries[0].Id;
            tmp.SetPassword(null, "TestPassword");
            userFactory.Save(tmp);
        }

        [TestMethod]
        public void User_ValidationPasses_WhenEmailAdressHasValidMatchInEmailRestrictions()
        {
            //reset first counry id to use in this test only
            _TestCountries[0].Site = _AlternateSite;
            _Context.SubmitChanges();

            EmailRestrictionFactory restrictionFactory = new EmailRestrictionFactory(_Context);
            UserFactory userFactory = new UserFactory(_Context);

            EmailRestriction restriction = new EmailRestriction(_AlternateSite.Id);
            restriction.EmailFilter = "[a-zA-Z0-9._]{0,}@testMail.com";
            restriction.Access = true;
            restrictionFactory.Save(restriction);

            User tmp = new User(_AlternateSite.Id);
            tmp.EmailAddress = "hello@testMail.com";
            tmp.FirstName = "First";
            tmp.LastName = "Last";
            tmp.CountryId = _TestCountries[0].Id;
            tmp.SetPassword(null, "TestPassword");
            userFactory.Save(tmp);
        }

        [TestMethod]
        public void User_GetByEmailAddress_WithCorrectSiteIdAndEmail_ReturnsNotNull()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.IsNotNull(factory.GetByEmailAddress(_TestSite.Id, _TestUsers[0].EmailAddress));
        }

        [TestMethod]
        public void User_GetByEmailAddress_WithCorrectSuperUsersEmail_ReturnsNotNull()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.IsNotNull(factory.GetByEmailAddress(_TestSite.Id, _TestSuperUsers[0].EmailAddress));
            Assert.IsNotNull(factory.GetByEmailAddress(_AlternateSite.Id, _TestSuperUsers[0].EmailAddress));
        }

        [TestMethod]
        public void User_GetByEmailAddress_WithIncorrectSiteId_ReturnsNull()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.IsNull(factory.GetByEmailAddress(_AlternateSite.Id, _TestUsers[0].EmailAddress));
        }

        [TestMethod]
        public void User_GetByEmailAddress_WithIncorrectEmail_ReturnsNull()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.IsNull(factory.GetByEmailAddress(_TestSite.Id, string.Concat("rubbish", _TestUsers[0].EmailAddress)));
        }

        [TestMethod]
        public void User_GetLoginKey_ForUserWithExistingLoginKey_ReturnsGuid()
        {
            UserFactory factory = new UserFactory(_Context);
            User tmp = factory.GetById(_TestUsers[0].Id);
            Assert.IsNotNull(tmp);
            Assert.AreEqual(_TestUserLoginKeys[0].Id, factory.GetLoginKey(tmp));
        }

        [TestMethod]
        public void User_GetLoginKey_ForUserWithOutExistingLoginKey_ReturnsGuid()
        {
            //create new user with no loing keys
            Dal.User tmpDalUser = new Dal.User();
            tmpDalUser.Anon = false;
            tmpDalUser.CountryId = _TestCountries[0].Id;
            tmpDalUser.Created = DateTime.UtcNow;
            tmpDalUser.EmailAddress = "allow@man.co.uk";
            tmpDalUser.FirstName = "";
            tmpDalUser.LastName = "";
            tmpDalUser.Password = "";

            _Context.Users.InsertOnSubmit(tmpDalUser);
            _Context.SubmitChanges();
            Assert.IsTrue(tmpDalUser.Id > 0);

            //Get bll user
            UserFactory factory = new UserFactory(_Context);
            User tmp = factory.GetById(tmpDalUser.Id);
            Assert.IsNotNull(tmp);

            Guid tmpKey = factory.GetLoginKey(tmp);
            Assert.IsNotNull(tmpKey);
            Assert.AreNotEqual(Guid.Empty, tmpKey);
            Assert.AreEqual(tmpKey, factory.GetLoginKey(tmp));
        }

        [TestMethod]
        public void User_GetByLoginKey_WithIncorrectKey_ReturnsNull()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.IsNull(factory.GetByLoginKey(Guid.NewGuid()));
        }

        [TestMethod]
        public void User_GetByLoginKey_WithCorrectKey_ReturnsNotNull()
        {
            UserFactory factory = new UserFactory(_Context);
            Assert.IsNotNull(factory.GetByLoginKey(_TestUserLoginKeys[0].Id));
        }

        [TestMethod]
        public void User_GetByLoginKey_WithCorrectKey_ReturnsCorrectUser()
        {
            UserFactory factory = new UserFactory(_Context);
            var tmp = factory.GetByLoginKey(_TestUserLoginKeys[3].Id);
            Assert.AreEqual(_TestUsers[3].Id, tmp.Id);
        }
    }
}
